package org.dizena.modules.auth.web;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.dizena.base.enums.State;
import org.dizena.base.shiro.SessionUserUtil;
import org.dizena.modules.master.bean.User;
import org.dizena.modules.master.service.UserService;
import org.dizena.modules.master.service.WebRootService;
import org.dizena.utils.EmailSendUtil;
import org.dizena.utils.ObjectUtil;
import org.dizena.utils.ThreadPoolUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;

@Controller
@RequestMapping("base")
public class AuthController
{
    @Resource
    private WebRootService service;
    @Resource
    private UserService userService;
    @Value("${server.domain")
    private String serverDomain;

    @Resource
    private EmailSendUtil emailSendUtil;

    @GetMapping("login")
    public String login()
    {
        service.initData();
        return "base/login";
    }

    @PostMapping("login")
    public String login(String u, String p, Model m)
    {
        try
        {
            UsernamePasswordToken token = new UsernamePasswordToken(u, p);
            Subject currentUser = SecurityUtils.getSubject();
            currentUser.login(token);
            if (currentUser.isAuthenticated())
            {
                userService.updateLoginTime();
                if (SessionUserUtil.checkRole("master"))
                {
                    return "redirect:/master";
                }
                return "redirect:/";
            }
            else
            {
                m.addAttribute("msg", "用户名或密码错误！");
                return "base/login";
            }
        } catch (Exception e)
        {
            m.addAttribute("msg", e.getMessage());
            return "base/login";
        }
    }

    @GetMapping("none")
    public String none()
    {
        return "base/none";
    }

    @GetMapping("logout")
    public String logout()
    {
        Subject currentUser = SecurityUtils.getSubject();
        try
        {
            currentUser.logout();
        } catch (Exception ignored)
        {
        }
        return "base/login";
    }

    @GetMapping("alter")
    public String alter(Model m)
    {
        User loginUser = SessionUserUtil.getSessionUser();
        m.addAttribute("cuser", loginUser);
        return "base/alter";
    }

    @PostMapping("alter")
    public String alter(String id, String p1, String p2, Model m)
    {
        if (p1.equals(p2) && p1.length() >= 6)
        {
            userService.alterPassword(id, p1, p2);
            return "redirect:/base/logout";
        }
        else
        {
            User loginUser = SessionUserUtil.getSessionUser();
            m.addAttribute("cuser", loginUser);
            m.addAttribute("msg", "两次密码输入不一致");
            return "base/alter";
        }
    }

    @GetMapping("register")
    public String register()
    {
        return "base/register";
    }

    @PostMapping("register")
    public String register(String email, String p1, String p2, Model m)
    {
        User account = userService.queryByAccount(email);
        if (account != null)
        {
            m.addAttribute("msg", "This email is register ever!");
            return "base/register";
        }
        else
        {
            if (!p1.equals(p2) || p1.length() < 6)
            {
                m.addAttribute("msg", "Illegal Password !");
                return "base/register";
            }

            account = new User();
            account.setAccount(email);
            account.setNickname(email);
            account.setRoles("user");
            account.setAuths("user:*:*");
            account.setLocked(State.UNLOCK.getState());
            account.setPasswd(p1);
            String res = userService.crud("add", account);
            if ("ok".equals(res))
            {
                ThreadPoolUtil.getPool().execute(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        String content = "Hi " + email + ", your account is ok and your password is: " + p1;
                        String title = "AuthController Success Info";
                        emailSendUtil.sendMail(email, content, title);
                    }
                });

                return "base/login";
            }
            else
            {
                m.addAttribute("msg", "AuthController fail !");
                return "base/register";
            }
        }
    }

    @GetMapping("forget")
    public String forget()
    {
        return "base/forget";
    }

    @PostMapping("forget")
    public String forget(String email)
    {
        User account = userService.queryByAccount(email);
        if (account != null)
        {
            ThreadPoolUtil.getPool().execute(new Runnable()
            {
                @Override
                public void run()
                {
                    String content = "Hi " + email + ", please click <a href=\"http://" + serverDomain + "/base/reset?id=" + account.getId() + "\">This Link</a> to update your password.";
                    String title = "Reset Password Info";
                    emailSendUtil.sendMail(email, content, title);
                }
            });
        }
        return "base/login";
    }

    @GetMapping("reset")
    public String reset(String id, Model m)
    {
        m.addAttribute("id", id);
        return "base/reset";
    }

    @PostMapping("reset")
    public String reset(String id, String p1, String p2, Model m)
    {
        if (p1.equals(p2) && p1.length() >= 6)
        {
            User tmp = new User();
            tmp.setId(id);
            tmp.setSalt(ObjectUtil.makeNumberStr(8));
            String pwd = DigestUtils.md5DigestAsHex((p1 + tmp.getSalt()).getBytes(StandardCharsets.UTF_8));
            tmp.setPasswd(pwd);
            userService.crud("edit", tmp);
            m.addAttribute("msg", "Password reset success");
        }
        return "base/login";
    }

}
